#include "MainWindows.h"
#include  <cstdlib>

namespace hps {
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent) {
    m_widget = new QWidget(this);
    m_layout = new QHBoxLayout;

    m_menuBar = new MenuBar(this);
    m_sideBar = new SideBarWindow(this, m_layout);
    m_editor = new EditorWindow(this);

    m_navigationWindows = new hps::NavigationWindows();

    m_splitter = new QSplitter(Qt::Horizontal);

    init();
    setMainWindowUi();
    rspFunc();
}

void MainWindow::init() {
    setWindowTitle("Note");
    this->resize(1200, 900);
    m_layout->setContentsMargins(0, 0, 0, 0);
    m_layout->setSpacing(0);
    m_splitter->setContentsMargins(0, 0, 0, 0);
    m_splitter->setHandleWidth(0);
    m_navigationWindows->setMinimumWidth(200);
}

void MainWindow::setMainWindowUi() {
    // 设置菜单栏UI
//    m_menuBar->setUi();
    setMenuBar(m_menuBar->getMenuBar());

    m_layout->insertWidget(0, m_sideBar);

    m_splitter->addWidget(m_navigationWindows);
    m_navigationWindows->hide();
    m_splitter->addWidget(m_editor);
    m_splitter->setSizes({200, 1200 - 240});
    m_layout->addWidget(m_splitter);
    m_widget->setLayout(m_layout);
    setCentralWidget(m_widget);
}

void MainWindow::rspFunc() {
    QObject::connect(m_sideBar->getNoteBookButton(),
                     &NoteBookButton::leftButtonClicked,
                     this,
                     &MainWindow::showNoteBookNavWindow);
    QObject::connect(m_sideBar->getNoteDirButton(),
                     &NoteBookDirButton::leftButtonClicked,
                     this,
                     &MainWindow::showNoteBookDirNavWindow);
    QObject::connect(m_sideBar->getSearchButton(),
                     &SearchButton::leftButtonClicked,
                     this,
                     &MainWindow::showSearchNavWindow);
    QObject::connect(m_sideBar->getHideButtonAction(),
                     &QAction::triggered,
                     this,
                     &MainWindow::hideSideBarButton);
    QObject::connect(m_navigationWindows->getNoteBookFileManager(),
                     &FileManager::doubleClicked,
                     this,
                     &MainWindow::openFile);
    QObject::connect(m_menuBar->getToHtmlAction(), &QAction::triggered, this, &MainWindow::changeMdToHtml);
    QObject::connect(m_menuBar->getToJsonAction(), &QAction::triggered, this, &MainWindow::changeMdToJson);
    QObject::connect(m_menuBar->getToXmlAction(), &QAction::triggered, this, &MainWindow::changeMdToXml);
    QObject::connect(m_menuBar->getToPdfAction(), &QAction::triggered, this, &MainWindow::changeMdToPdf);

    QObject::connect(m_menuBar->getAddBook(), &QAction::triggered, this, &MainWindow::addNoteBook);
    QObject::connect(m_menuBar->getOpenBook(), &QAction::triggered, this, &MainWindow::openNoteBook);
    QObject::connect(m_menuBar->getSaveFile(), &QAction::triggered, this, &MainWindow::saveCurrentFile);
    QObject::connect(m_menuBar->getAddNote(), &QAction::triggered, this, &MainWindow::addNote);
    QObject::connect(m_menuBar->getOpenNote(), &QAction::triggered, this, &MainWindow::openNote);
}

void MainWindow::hideNavWindows() {
    m_navigationWindows->hideAllNav();
    m_sideBar->setNowOpenButtonName(ButtonName::unknow);
    m_sideBar->restoreAllColor();
    m_navigationWindows->hide();
}
void MainWindow::showNoteBookNavWindow() {
    auto nowButtonName = m_sideBar->getNowOpenButtonName();
    auto buttonName = ButtonName::noteBook;
    if (buttonName == nowButtonName) { // 关闭导航栏
        hideNavWindows();
        return;
    } else { // 其他导航栏正在被打开
        hideNavWindows();
    }
    m_navigationWindows->showNoteBookNav();
    m_sideBar->setNowOpenButtonName(ButtonName::noteBook);
    m_sideBar->setClickedColor(m_sideBar->getNoteBookButton());
    m_navigationWindows->show();
}
void MainWindow::showNoteBookDirNavWindow() {
    auto nowButtonName = m_sideBar->getNowOpenButtonName();
    auto buttonName = ButtonName::noteBookDir;
    if (buttonName == nowButtonName) { // 关闭导航栏
        hideNavWindows();
        return;
    } else { // 其他导航栏正在被打开
        hideNavWindows();
    }
    m_navigationWindows->showNoteBookDirNav();
    m_sideBar->setNowOpenButtonName(ButtonName::noteBookDir);
    m_sideBar->setClickedColor(m_sideBar->getNoteDirButton());
    m_navigationWindows->show();
}
void MainWindow::showSearchNavWindow() {
    auto nowButtonName = m_sideBar->getNowOpenButtonName();
    auto buttonName = ButtonName::search;
    if (buttonName == nowButtonName) { // 关闭导航栏
        hideNavWindows();
        m_navigationWindows->hide();
        return;
    } else { // 其他导航栏正在被打开
        hideNavWindows();
    }
    m_navigationWindows->showSearchNav();
    m_sideBar->setNowOpenButtonName(ButtonName::search);
    m_sideBar->setClickedColor(m_sideBar->getSearchButton());
    m_navigationWindows->show();
}
void MainWindow::hideSideBarButton() {
    auto rightClickedButtonName = m_sideBar->getRightClickedButtonName();
    if (rightClickedButtonName == ButtonName::unknow) {
        std::cerr << "when hiding button error in: " << __FILE__ << ":" << __LINE__ << std::endl;
        return;
    } else if (rightClickedButtonName == ButtonName::noteBook) {
        if (m_sideBar->getNowOpenButtonName() == rightClickedButtonName) {
            hideNavWindows();
        }
        m_sideBar->removeButton(m_sideBar->getNoteBookButton(), rightClickedButtonName);
    } else if (rightClickedButtonName == ButtonName::noteBookDir) {
        if (m_sideBar->getNowOpenButtonName() == rightClickedButtonName) {
            hideNavWindows();
        }
        m_sideBar->removeButton(m_sideBar->getNoteDirButton(), rightClickedButtonName);
    } else if (rightClickedButtonName == ButtonName::search) {
        if (m_sideBar->getNowOpenButtonName() == rightClickedButtonName) {
            hideNavWindows();
        }
        m_sideBar->removeButton(m_sideBar->getSearchButton(), rightClickedButtonName);
    } else {
        std::cerr << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << " -- not have Type in this function."
                  << std::endl;
    }
}
void MainWindow::openFile(const QModelIndex &index) {
    // 获取双击项对应的数据模型索引
    QVariant data = index.data(Qt::UserRole);
    // 将数据转换为 QFileInfo
    auto filePath = data.toString();
    QFileInfo fileInfo(filePath);

    if (fileInfo.isDir()) {
        return;
    }

    m_editor->addEditPage(filePath.toStdString());
}
void MainWindow::changeMdToHtml() {
    // 判断是不是md文件
    EditorBase *editor = (EditorBase *) m_editor->getTabWidget()->currentWidget();
    if (! editor) {
        QMessageBox::warning(this, "警告", "被转换文本未打开 -> editor null!");
        return;
    }
    std::string filePath = editor->getFilePath();

    if (filePath.empty()) {
        QMessageBox::warning(this, "警告", "EditorName null!");
        std::cerr << "changeMdToHtml editorName is empty.\t" << __FILE__ << ":" << __LINE__ << std::endl;
        return;
    }
    int idx = filePath.size() - 1;
    while (filePath[idx] != '.')
        idx --;
    std::string type = filePath.substr(idx + 1);
    if (type != "md") {
        QMessageBox::warning(this, "警告", "当前被转换的文件不是MarkDown文件");
        std::cerr << "changeMdToHtml editorName source file is not .md\t" << __FILE__ << ":" << __LINE__ << std::endl;
        return;
    }

    std::string outputFileName = filePath.substr(0, idx - 0);
    outputFileName += ".html";
    std::string cmd = "pandoc " + editor->getFilePath() + " -o " + outputFileName;

    int result = std::system(cmd.c_str());
    if (result != 0) {
        QMessageBox::critical(this, "error", "result != 0");
        std::cerr << "change errorCode: " << result << std::endl;
    } else {
        QMessageBox::information(this, "成功", "转换成功，请在笔记本中查看！");
    }
    m_navigationWindows->getNoteBookNav()->flush();
}
void MainWindow::changeMdToJson() {
// 判断是不是md文件
    EditorBase *editor = (EditorBase *) m_editor->getTabWidget()->currentWidget();
    if (! editor) {
        QMessageBox::warning(this, "警告", "被转换文本未打开 -> editor null!");
        return;
    }
    std::string filePath = editor->getFilePath();

    if (filePath.empty()) {
        QMessageBox::warning(this, "警告", "EditorName null!");
        std::cerr << "changeMdToHtml editorName is empty.\t" << __FILE__ << ":" << __LINE__ << std::endl;
        return;
    }
    int idx = filePath.size() - 1;
    while (filePath[idx] != '.')
        idx --;
    std::string type = filePath.substr(idx + 1);
    if (type != "md") {
        QMessageBox::warning(this, "警告", "当前被转换的文件不是MarkDown文件");
        std::cerr << "changeMdToHtml editorName source file is not .md\t" << __FILE__ << ":" << __LINE__ << std::endl;
        return;
    }

    std::string outputFileName = filePath.substr(0, idx - 0);
    outputFileName += ".json";
    std::string cmd = "pandoc " + editor->getFilePath() + " -o " + outputFileName;

    int result = std::system(cmd.c_str());
    if (result == 0) {
        QMessageBox::information(this, "成功", "转换成功，请在笔记本中查看");
    } else {
        QMessageBox::critical(this, "error", "change json result != 0");
    }
    m_navigationWindows->getNoteBookNav()->flush();
}
void MainWindow::changeMdToXml() {
    // 判断是不是md文件
    EditorBase *editor = (EditorBase *) m_editor->getTabWidget()->currentWidget();
    if (! editor) {
        QMessageBox::warning(this, "警告", "被转换文本未打开 -> editor null!");
        return;
    }
    std::string filePath = editor->getFilePath();

    if (filePath.empty()) {
        QMessageBox::warning(this, "警告", "EditorName null!");
        std::cerr << "changeMdToHtml editorName is empty.\t" << __FILE__ << ":" << __LINE__ << std::endl;
        return;
    }
    int idx = filePath.size() - 1;
    while (filePath[idx] != '.')
        idx --;
    std::string type = filePath.substr(idx + 1);
    if (type != "md") {
        QMessageBox::warning(this, "警告", "当前被转换的文件不是MarkDown文件");
        std::cerr << "changeMdToHtml editorName source file is not .md\t" << __FILE__ << ":" << __LINE__ << std::endl;
        return;
    }

    std::string outputFileName = filePath.substr(0, idx - 0);
    outputFileName += ".html";
    std::string cmd = "pandoc " + editor->getFilePath() + " -o " + outputFileName;

    int result = std::system(cmd.c_str());
    if (result != 0) {
        QMessageBox::critical(this, "error", "change json result != 0");
        std::cerr << "change errorCode: " << result << std::endl;
    }
}
void MainWindow::addNoteBook() {
    AddNoteBookData noteBookData;
    AddNoteBookDialog *dialog = new hps::AddNoteBookDialog(&noteBookData);
    if (dialog->exec() == QDialog::Rejected)
        return;

    // 创建文件夹
    std::string cmd = "mkdir " + noteBookData._path + "/" + noteBookData._name;
    std::string result = hps::system(cmd.c_str());
    if (! result.empty()) {
        std::cerr << result << " " << __FILE__ << ":" << __LINE__ << std::endl;
    }

    // 创建配置文件
    boost::json::object j;
    j["name"] = noteBookData._name;
    j["path"] = noteBookData._path;
    j["information"] = noteBookData._information;
    j["createTime"] = hps::TimeFormat(hps::GetCurrentMS());
    j["updateTime"] = hps::TimeFormat(hps::GetCurrentMS());
    std::ofstream outputFile(noteBookData._path + "/" + noteBookData._name + "/" + "vx.json");
    if (! outputFile.is_open()) {
        std::cerr << "Create noteBook config file failed. " << __FILE__ << ":" << __LINE__ << std::endl;
    }
    outputFile << boost::json::serialize(j);
    outputFile.close();

    // 修改数据库
    std::string path = noteBookData._path + "/" + noteBookData._name;
    CONFIG()->addNoteBook(noteBookData._name, path);
    CONFIG()->updateDataBaseTime();

    m_navigationWindows->getNoteBookNav()->flushNoteBookChooser();

    delete dialog;
}
void MainWindow::openNoteBook() {
    QString bookPath = QFileDialog::getExistingDirectory(nullptr, "打开文件", QDir::homePath());
    if (bookPath.isEmpty()) {
        return;
    }

    std::string name = hps::getNameFromDir(bookPath.toStdString());
    std::string path = "";
    if (bookPath.toStdString().back() == '/') {
        int s = bookPath.toStdString().size();
        path = bookPath.toStdString().substr(0, s - 1);
    } else {
        path = bookPath.toStdString();
    }
    AddNoteBookData noteBookData;
    noteBookData._name = name;
    noteBookData._path = path;

    // 创建配置文件
    boost::json::object j;
    j["name"] = name;
    j["path"] = noteBookData._path;
    j["createTime"] = hps::TimeFormat(hps::GetCurrentMS());
    j["updateTime"] = hps::TimeFormat(hps::GetCurrentMS());
    std::ofstream outputFile(noteBookData._path + "/" + "vx.json");
    if (! outputFile.is_open()) {
        std::cerr << "Create noteBook config file failed. " << __FILE__ << ":" << __LINE__ << std::endl;
    }
    outputFile << boost::json::serialize(j);
    outputFile.close();

    // 修改数据库
    std::string dataBasePath = noteBookData._path;
    CONFIG()->addNoteBook(noteBookData._name, dataBasePath);
    CONFIG()->updateDataBaseTime();

    m_navigationWindows->getNoteBookNav()->flushNoteBookChooser();

    try {
        auto fileManager = m_navigationWindows->getNoteBookNav()->getFileManager();
        fileManager->freeItems();
        fileManager->loadNoteBook(QString(path.c_str()), fileManager->invisibleRootItem());
    }
    catch (std::exception &e) {
        std::cerr << e.what() << std::endl;
    }
}
void MainWindow::saveCurrentFile() {
    auto tabWidget = m_editor->getTabWidget();
    if (tabWidget == nullptr) {
        QMessageBox::critical(this, "Error", "TabWidget is Null!");
        return;
    }
    auto editor = (EditorBase *) tabWidget->currentWidget();
    if (editor == nullptr) {
        QMessageBox::warning(this, "Warning", "目前没有打开的文件!");
        return;
    }

//    auto type = m_editor->checkFileType(editor->getFileName());
    editor->saveFile();
}
void MainWindow::addNote() {
    auto editor = (EditorBase *) m_editor->getTabWidget()->currentWidget();
    if (editor == nullptr) {
        QMessageBox::warning(this, "Warning", "未找到可以选择的笔记本");
        return;
    }
    std::string path = editor->getFilePath();
    int idx = path.size() - 1;
    while (idx >= 0 && path[idx] != '/')
        idx --;
    path = path.substr(0, idx);
    AddNoteData data;

    AddNoteDialog *dialog = new AddNoteDialog(&data, path);

    if (dialog->exec() == QDialog::Rejected) {
        return;
    }

    if (path.back() != '/')
        path += "/";

    std::string cmd = "touch " + path + data._noteName;
    std::cout << cmd << std::endl;

    std::string result = hps::system(cmd.c_str());
    if (! result.empty()) {
        QMessageBox::critical(this, "Error", "Add note Error!");
        std::cerr << result << " " << __FILE__ << ":" << __LINE__ << std::endl;
    }
    m_navigationWindows->getNoteBookNav()->flush();
    delete dialog;
}
void MainWindow::openNote() {
    // 打开文件选择对话框
    QString filePath =
        QFileDialog::getOpenFileName(nullptr, "Select File", QDir::homePath(), "All Files (*);;Text Files (*.txt)");

    // 检查用户是否选择了文件
    if (! filePath.isEmpty()) {
        m_editor->addEditPage(filePath.toStdString());
    } else {
        return;
    }
}
void MainWindow::changeMdToPdf() {
    auto editor = (EditorBase *) m_editor->getTabWidget()->currentWidget();
    editor->saveFile();
    if (editor == nullptr) {
        QMessageBox::critical(this, "Errot", "请选择MarkDown文件!");
        return;
    }
    std::string filePath = editor->getFilePath();

    if (m_editor->checkFileType(filePath) != FileType::markDown) {
        QMessageBox::critical(this, "Errot", "请选择MarkDown文件!");
        return;
    }

    // 先转化为html
    std::string dirPath = "";
    int idx = filePath.size() - 1;
    while (idx >= 0 && filePath[idx] != '/')
        idx --;
    int idx1 = editor->getFileName().size() - 1;
    auto fileName = editor->getFileName();
    while (idx >= 0 && fileName[idx1] != '.')
        idx1 --;
    dirPath = filePath.substr(0, idx);
    fileName = fileName.substr(0, idx1);
    std::string htmlFileName = "bck" + fileName;
    std::string htmlFilePath = dirPath + "/" + htmlFileName + ".html";
    std::string makeHtmlCmd = "pandoc " + filePath + " -o " + htmlFilePath;
    int result = std::system(makeHtmlCmd.c_str());
    if (result != 0) {
        QMessageBox::critical(this, "Error", "To pdf：change html error!");
        std::cerr << "To pdf：change html error! " << __FILE__ << ":" << __LINE__ << std::endl;
        return;
    }

    QFile htmlFile(htmlFilePath.c_str());
    if (! htmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QMessageBox::critical(this, "Error", "打开Html失败");
        return;
    }

    QString htmlContent;
    QTextStream in(&htmlFile);
    htmlContent = in.readAll();

    QTextDocument *document = new QTextDocument();
    document->setHtml(htmlContent);

    QPrinter printer(QPrinter::HighResolution);
    printer.setPageSize(QPrinter::A4);
    printer.setOutputFormat(QPrinter::PdfFormat);

    std::string pdfFilePath = dirPath + "/" + fileName + ".pdf";

    printer.setOutputFileName(pdfFilePath.c_str());
    document->print(&printer);

    std::string rmHtmlFile = "rm -r " + htmlFilePath;
    result = std::system(rmHtmlFile.c_str());
    if (result != 0) {
        QMessageBox::critical(this, "Error", "To pdf：delete html error!");
        std::cerr << "To pdf：delete html error! " << __FILE__ << ":" << __LINE__ << std::endl;
        delete document;
        return;
    }
    m_navigationWindows->getNoteBookNav()->flush();
    delete document;
}
}
